package org.example.service.user;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.example.dao.dao.user.UStudentDao;
import org.example.dao.dto.user.CalenderDto;
import org.example.dao.entity.user.UStudent;
import org.example.exception.JwErrorException;
import org.example.exception.ParamLossErrorException;
import org.example.skytool.commom.ContextUtil;
import org.example.skytool.commom.IdWorker;
import org.example.skytool.date.TimeZoneUtil;
import org.example.skytool.jw.JwUtil;
import org.example.skytool.jw.dao.Exam;
import org.example.skytool.jw.dao.PscjInfo;
import org.example.skytool.jw.dao.Score;
import org.example.skytool.jw.dao.WeekCourse;
import org.example.skytool.jw.dao.PageGetter;
import org.example.skytool.jw.dao.ParseHtmlServiceImpl;
import org.example.skytool.redis.RedisConstants;
import org.example.skytool.redis.RedisUtils;
import org.example.skytool.security.EncodeUtil;
import org.example.utils.oaa.RedisOaaService;
import org.example.utils.user.RedisJwService;
import org.example.utils.user.RedisUserService;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

/**
 * @author 22449
 */
@Service("jwService")
@Slf4j
public class JwServiceImpl {

    @Resource
    private ContextUtil contextUtil;


    @Resource
    private PageGetter pageGetter;

    @Resource
    private ParseHtmlServiceImpl parseHtmlService;

    @Resource
    private RedisJwService redisJwService;

    private static final SimpleDateFormat DAY_SDF = new SimpleDateFormat("yyyy-MM-dd");

    private int calculateResult(LocalDate localDate) {
        LocalDate sep3 = LocalDate.of(2023, 9, 3); // 设置9月3日
        int temp = (int) (localDate.toEpochDay() - sep3.toEpochDay());
        if (temp < 0) {
            return 0;
        }
        int days = (int) ((localDate.toEpochDay() - sep3.toEpochDay()) / 7) + 1;
        return days;
    }

    public List<CalenderDto> getWeekDataInfo(Integer nowWeek) {
        List<CalenderDto> list = redisJwService.getWeekInfo(nowWeek.toString());
        if(list!=null&&list.size()!=0){
            return list;
        }
        list = new ArrayList<>();
        // 将时间戳转换为LocalDateTime
        LocalDateTime dateTime = LocalDateTime.ofInstant(new Date().toInstant(),
                java.time.ZoneId.systemDefault());
        String cookie = contextUtil.getCookie();
        Integer num = Integer.valueOf(getNowWeekDate(cookie));
        while (!num.equals(nowWeek)) {
            if (num < nowWeek) {
                dateTime = dateTime.plusDays(7);
            } else {
                dateTime = dateTime.plusDays(-7);
            }
            LocalDate currentDate1 = dateTime.toLocalDate();
            num = calculateResult(currentDate1);
        }
        // 将LocalDateTime转换为LocalDate
        LocalDate currentDate = dateTime.toLocalDate();
        // 获取当前日期
        // 获取当前日期对应的星期几（从1开始，1代表星期一）
        int currentDayOfWeek = currentDate.getDayOfWeek().getValue();
        // 获取上周的周日日期
        LocalDate lastSunday;
        if (currentDayOfWeek == 7) {
            lastSunday = currentDate;
        } else {
            lastSunday = currentDate.with(TemporalAdjusters.previous(DayOfWeek.SUNDAY));
        }
        currentDayOfWeek = 7;
        // 将上周的周日日期和对应的星期几存入HashMap
        list.add(new CalenderDto(lastSunday, currentDayOfWeek));
        // 将本周的日期和对应的星期几存入HashMap，从周日到周六
        for (int i = 1; i < 7; i++) {
            LocalDate nextDate = lastSunday.plusDays(i);
            int dayNumber = nextDate.getDayOfWeek().getValue();
            list.add(new CalenderDto(nextDate, dayNumber));
        }
        redisJwService.setWeekInfo(nowWeek.toString(),list);
        return list;
    }


    public Map<String, Object> getBasicData() {
        //从缓存获取
        Map<String, Object> data = null;
        data = new LinkedHashMap<>();
        String cookie = contextUtil.getCookie();
        String nowSemester = getNowSemester(cookie);
        data.put("nowSemester", nowSemester);
        String nowWeekData = getNowWeekDate(cookie);
        data.put("nowWeek", nowWeekData); //当前第几周
        WeekCourse[][] courses = getCourse(nowSemester,Integer.valueOf(nowWeekData));
        data.put("courses",courses);
        String nowData = TimeZoneUtil.getNowTime();
        data.put("nowData",nowData);
        List<CalenderDto> list = getWeekDataInfo(Integer.valueOf(nowWeekData));
        data.put("nowWeekInfo",list);
        return data;
    }


    /**
     * 获得现在是第几学期
     */
    private String getNowSemester(String cookie) {
        String nowSemester = redisJwService.getSemesterNow();
        if (nowSemester != null) {
            return nowSemester;
        }
        try {
            String htmlText = pageGetter.getSemesterPage(cookie);
            Document document = Jsoup.parse(htmlText);
            Element xnxq01id = document.getElementById("xnxq01id");
            Elements select = xnxq01id.select("[selected=selected]");
            nowSemester = select.text();
            redisJwService.setSemesterNow(nowSemester);
            return nowSemester;
        } catch (Exception e) {
            throw new JwErrorException("教务系统无响应！");
        }

    }


    public String getNowWeekDate(String cookie) {
        String nowWeek = redisJwService.getWeekNow();
        if(nowWeek!=null){
            return nowWeek;
        }
        String htmlText;
        try {
            htmlText = pageGetter.getWeekDatePage(cookie);
        } catch (Exception e) {
            throw new JwErrorException("访问失败");
        }
        List<Integer> nowWeekDate = parseHtmlService.parseWeekDateHtml(htmlText);
        nowWeek = nowWeekDate.get(0).toString();
        redisJwService.setWeekNow(nowWeek);
        return nowWeek;
    }


    /**
     * 查看某一周的课表
     *
     * @param zc    看第几周的课表(必须在1-20)之间
     * @param xueqi 看哪个学期的课表
     */
    public WeekCourse[][] getCourse(String xueqi, Integer zc) {
        String cookie = contextUtil.getCookie();
        String htmlText;
        try {
            htmlText = pageGetter.getCoursePage(cookie, xueqi, zc);
        } catch (Exception e) {
            return null;
        }
        WeekCourse[][] weekCourses = parseHtmlService.parseCourseHtml(htmlText);
        return weekCourses;
    }

    public List<String> getAllSemester() {
        String id = contextUtil.getId().toString();
        //获取stuNum
        LambdaQueryWrapper<UStudent> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UStudent::getIsValid, 1);
        lambdaQueryWrapper.eq(UStudent::getUserId, id);
        UStudent uStudent = uStudentDao.selectOne(lambdaQueryWrapper);
        String studentNum = uStudent.getStuNum();
        String cookie = contextUtil.getCookie();
        int rxYear = Integer.parseInt(studentNum.substring(0, 4));
        List<String> list = redisJwService.getSemesterTotal(String.valueOf(rxYear));
        if(list!=null&&list.size()!=0){
            return list;
        }
        String nowXueqi = getNowSemester(cookie);
        int nowYear = Integer.parseInt(nowXueqi.substring(0, 4));
        list = new LinkedList<>();
        if (isFirstSemester(nowXueqi)) {
            for (int i = rxYear; i <= nowYear; i++) {
                list.add(i + "-" + (i + 1) + "-1");
                list.add(i + "-" + (i + 1) + "-2");
            }
        } else {
            int i = rxYear;
            for (; i <= nowYear; i++) {
                list.add(i + "-" + (i + 1) + "-1");
                list.add(i + "-" + (i + 1) + "-2");
            }
            list.add(i + "-" + (i + 1) + "-1");
        }

        redisJwService.setSemesterTotal(String.valueOf(rxYear),list);
        return list;
    }

    private boolean isFirstSemester(String nowXueqi) {
        try {
            String[] strings = nowXueqi.split("-");
            if ("1".equals(strings[2])) {
                //如果是第一学期
                return true;
            } else {
                return false;
                //如果是第二学期
            }
        } catch (Exception e) {
            throw new RuntimeException("系统错误,缓存可能超时");
        }
    }

    /**
     * 获取考试安排
     *
     * @param xueqi 学期
     * @return {@link List<     Exam     >}
     */
    public List<Exam> getExamArrangement(String xueqi) {
        String htmlText;
        String cookie = contextUtil.getCookie();
        try {
            htmlText = pageGetter.getExamPlansPage(cookie, xueqi);
        } catch (Exception e) {
            throw new RuntimeException("教务系统无响应！");
        }
        List<Exam> examList = parseHtmlService.parseExamArrangementHtml(htmlText);
        return examList;
    }

    /**
     * 查询某一学期所有成绩列表
     *
     * @param xueqi 学期
     * @return {@link Score}
     */
    public List<Score> getScoreList(String xueqi) {
        String cookie = contextUtil.getCookie();
        String htmlText;
        try {
            htmlText = pageGetter.getScorePage(cookie, xueqi);
        } catch (Exception e) {
            throw new RuntimeException("教务系统无响应！");
        }
        List<Score> scoreList = parseHtmlService.parseScoreHtml(htmlText);
        return scoreList;
    }

    /**
     * 查询某一项成绩详情
     *
     * @param pscjUrl 查询成绩返回的pscjUrl
     * @return {@link PscjInfo}
     */
    public PscjInfo getScoreDetail(String pscjUrl) {
        String cookie = contextUtil.getCookie();
        String htmlText;
        try {
            htmlText = pageGetter.getScoreDetailPage(cookie, pscjUrl);
        } catch (Exception e) {
            throw new RuntimeException("教务系统无响应！");
        }
        PscjInfo pscjInfo = parseHtmlService.parseScoreDetailHtml(htmlText);
        return pscjInfo;
    }

    @Resource
    private JwUtil jwUtil;

    @Resource
    private IdWorker idWorker;

    @Resource
    private UStudentDao uStudentDao;

    @Resource
    private RedisUserService redisUserService;

    public UStudent bindJw(String stuNum, String password) {
        Long userId = contextUtil.getId();
        LambdaQueryWrapper<UStudent> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UStudent::getIsValid, 1);
        lambdaQueryWrapper.eq(UStudent::getUserId, userId);
        UStudent student = uStudentDao.selectOne(lambdaQueryWrapper);
        if (student == null) {
            String cookie = jwUtil.getLoginCookie(stuNum, password);
            student = jwUtil.getStuInfo(cookie);
            student.setUserId(userId);
            student.setId(idWorker.nextId());
            student.setPassword(EncodeUtil.encrypt(password));
            uStudentDao.insert(student);
        }
        redisUserService.delUserDto(userId.toString());
        return student;
    }

    public Boolean judge() {
        Boolean flag = false;
        String userId = contextUtil.getId().toString();
        LambdaQueryWrapper<UStudent> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UStudent::getIsValid, 1);
        lambdaQueryWrapper.eq(UStudent::getUserId, userId);
        UStudent student = uStudentDao.selectOne(lambdaQueryWrapper);
        if (student == null) {
            flag = false;
        } else {
            String stuNum = student.getStuNum();
            String password = EncodeUtil.decrypt(student.getPassword());
            String cookie = jwUtil.getLoginCookie(stuNum, password);
            redisUserService.setCacheCookie(userId, cookie);
            flag = true;
        }
        return flag;
    }

    public void unbindJw() {
        Long userId = contextUtil.getId();
        LambdaQueryWrapper<UStudent> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UStudent::getUserId,userId);
        lambdaQueryWrapper.eq(UStudent::getIsValid,1);
        UStudent student = uStudentDao.selectOne(lambdaQueryWrapper);
        if(student==null){
            throw new ParamLossErrorException("没有绑定教务");
        }
        student.setIsValid(0);
        uStudentDao.updateById(student);
    }


}
